package cn.yunyichina.provider.pay.alipay.service.impl;

import cn.yunyichina.provider.iface.entity.alipay.AlipayFacepayMedicalCardQueryRequest;
import cn.yunyichina.provider.iface.entity.alipay.AlipayFacepayMedicalCardQueryResponse;
import cn.yunyichina.provider.iface.entity.alipay.AlipayWebpayMedicalCardQueryRequest;
import cn.yunyichina.provider.iface.entity.alipay.AlipayWebpayMedicalCardQueryResponse;
import cn.yunyichina.provider.iface.entity.common.CityCode;
import cn.yunyichina.provider.iface.entity.common.ResCommon;
import cn.yunyichina.provider.iface.entity.common.ResponseObject;
import cn.yunyichina.provider.iface.entity.pay.alipay.MedicareResponse;
import cn.yunyichina.provider.iface.entity.pay.alipay.MedicareVo;
import cn.yunyichina.provider.pay.alipay.config.Alipay;
import cn.yunyichina.provider.pay.alipay.constant.ResponseEnum;
import cn.yunyichina.provider.pay.alipay.entity.MedicalCardQueryResponse;
import cn.yunyichina.provider.pay.alipay.service.AlipayMedicareService;
import cn.yunyichina.provider.pay.alipay.service.BaseTradeService;
import cn.yunyichina.provider.pay.alipay.utils.HttpUtil;
import cn.yunyichina.utils.commons.DateUtils;
import cn.yunyichina.utils.commons.StringUtils;
import cn.yunyichina.utils.convert.JsonUtils;
import cn.yunyichina.utils.convert.MapUtils;
import cn.yunyichina.utils.network.HttpsUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayCommerceMedicalCardQueryRequest;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.response.AlipayCommerceMedicalCardQueryResponse;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
public class AlipayMedicareServiceImpl extends BaseTradeService implements AlipayMedicareService {

    private static final Logger logger = LoggerFactory.getLogger(AlipayTradeServiceImpl.class);

    public ResCommon<AlipayFacepayMedicalCardQueryResponse> queryAlipayFacepayMedicare(AlipayFacepayMedicalCardQueryRequest request) {
        logger.info("AlipayMedicareServiceImpl.queryAlipayFacepayMedicare.request -> {}", JSON.toJSONString(request));

        ResCommon<AlipayFacepayMedicalCardQueryResponse> response = new ResCommon<>();

        try {
            AlipayClient alipayClient = new DefaultAlipayClient(
//                "http://openapi.dl.alipaydev.com/gateway.do",
                    this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI),
                    request.getAppId(),
                    request.getPrivateKey(),
                    request.getFormat(),
                    request.getCharset(),
                    request.getPublicKey(),
                    request.getSignType()
            );

            AlipayCommerceMedicalCardQueryRequest alipayCommerceMedicalCardQueryRequest = new AlipayCommerceMedicalCardQueryRequest();
            alipayCommerceMedicalCardQueryRequest.setBizContent(request.getBizContent());
            logger.info("AlipayMedicareServiceImpl.queryAlipayFacepayMedicare.alipayCommerceMedicalCardQueryRequest -> {}", JsonUtils.toJsonString(alipayCommerceMedicalCardQueryRequest));

            AlipayCommerceMedicalCardQueryResponse alipayCommerceMedicalCardQueryResponse = alipayClient.execute(alipayCommerceMedicalCardQueryRequest);
            logger.info("AlipayMedicareServiceImpl.queryAlipayFacepayMedicare.alipayCommerceMedicalCardQueryResponse -> {}", JsonUtils.toJsonString(alipayCommerceMedicalCardQueryResponse));

            MedicalCardQueryResponse medicalCardQueryResponse = JsonUtils.parseObject(alipayCommerceMedicalCardQueryResponse.getBody(), MedicalCardQueryResponse.class);
            MedicalCardQueryResponse.AlipayCommerceMedicalCardQueryResponse customAlipayCommerceMedicalCardQueryResponse = medicalCardQueryResponse.getAlipayCommerceMedicalCardQueryResponse();
            if (alipayCommerceMedicalCardQueryResponse.isSuccess()) {
                AlipayFacepayMedicalCardQueryResponse alipayFacepayMedicalCardQueryResponse = new AlipayFacepayMedicalCardQueryResponse();
                BeanUtils.copyProperties(customAlipayCommerceMedicalCardQueryResponse, alipayFacepayMedicalCardQueryResponse);
                logger.info("AlipayMedicareServiceImpl.queryAlipayFacepayMedicare.alipayFacepayMedicalCardQueryResponse -> {}", JsonUtils.toJsonString(alipayFacepayMedicalCardQueryResponse));

                response.setResult(alipayFacepayMedicalCardQueryResponse);
            } else {
                response.setResultCodeAndMessage(
                        ResponseEnum.ALIPAY_MEDICARE_CARD_QUERY_FAILURE.getCode(),
                        ResponseEnum.ALIPAY_MEDICARE_CARD_QUERY_FAILURE.getMessage()
                );
            }
        } catch (Exception e) {
            logger.error("AlipayMedicareServiceImpl.queryAlipayFacepayMedicare.Exception", e);
        }

        return response;
    }

    private Map<String, String> buildMedicareQueryMap(AlipayWebpayMedicalCardQueryRequest request) {
        Map<String, String> result = new HashMap<>();

        result.put("app_id", request.getAppId());
        result.put("method", request.getMethod());
        result.put("sign_type", request.getSignType());
        result.put("timestamp", request.getTimestamp());
        result.put("version", request.getVersion());

        result.put("sign_flag", request.getSignFlag());

        result.put("buyer_id", request.getBuyerId());
        result.put("card_org_no", request.getCardOrgNo());

        return result;
    }

    private Map<String, String> buildMedicareBindMap(AlipayWebpayMedicalCardQueryRequest request) {
        Map<String, String> result = new HashMap<>();

        result.put("method", "alipay.commerce.medical.instcard.bind");
        result.put("app_id", request.getAppId());
        result.put("sign_type", request.getSignType());
        result.put("timestamp", request.getTimestamp());
        result.put("version", request.getVersion());

        result.put("sign_flag", request.getSignFlag());

        result.put("auth_token", request.getAccessToken());
        result.put("buyer_id", request.getBuyerId());
//        result.put("return_url", request.getReturnUrl());

        result.put("city_code", CityCode.SHENZHEN);

        return result;
    }

    public ResCommon<Object> queryAlipayWebpayMedicare(AlipayWebpayMedicalCardQueryRequest request) {
        logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.request -> {}", JSON.toJSONString(request));

        ResCommon<Object> response = new ResCommon<>();

        AlipayClient alipayClient = new DefaultAlipayClient(
                this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI),
                request.getAppId(),
                request.getPrivateKey(),
                request.getFormat(),
                request.getCharset(),
                request.getPublicKey(),
                request.getSignType()
        );

        AlipaySystemOauthTokenRequest oauthTokenRequest = new AlipaySystemOauthTokenRequest();
        oauthTokenRequest.setCode(request.getAuthCode());
        oauthTokenRequest.setGrantType("authorization_code");
        logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.oauthTokenRequest -> {}", JsonUtils.toJsonString(oauthTokenRequest));
        try {
            AlipaySystemOauthTokenResponse oauthTokenResponse = alipayClient.execute(oauthTokenRequest);
            logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.oauthTokenResponse -> {}", JsonUtils.toJsonString(oauthTokenResponse));

            if (oauthTokenResponse != null && oauthTokenResponse.isSuccess()) {
                request.setBuyerId(oauthTokenResponse.getUserId());

                Map<String, String> queryMap = this.buildMedicareQueryMap(request);
                logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.queryMap -> {}", JsonUtils.toJsonString(queryMap));

                String originParams = MapUtils.convertMap2String(queryMap);
                logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.originParams -> {}", originParams);

                String encodedParams = MapUtils.convertMap2UrlEncodeString(queryMap, request.getCharset());
                logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.encodedParams -> {}", encodedParams);

                String params;
                if ("RSA".equals(request.getSignType())) {
                    params = encodedParams + "&sign=" + URLEncoder.encode(AlipaySignature.rsaSign(originParams, request.getPrivateKey(), request.getCharset()), request.getCharset());
                } else {
                    params = encodedParams + "&sign=" + URLEncoder.encode(AlipaySignature.rsa256Sign(originParams, request.getPrivateKey(), request.getCharset()), request.getCharset());
                }

                String url = this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI) + "?" + params;
                logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.url -> {}", url);

                String result = HttpUtil.get(url);
                logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.result -> {}", result);

                AlipayWebpayMedicalCardQueryResponse queryResponse = JsonUtils.parseObject(result, AlipayWebpayMedicalCardQueryResponse.class);
                logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.queryResponse -> {}", JsonUtils.toJsonString(queryResponse));

                AlipayWebpayMedicalCardQueryResponse.AlipayCommerceMedicalCardQueryResponse alipayCommerceMedicalCardQueryResponse = queryResponse.getAlipayCommerceMedicalCardQueryResponse();
                logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.alipayCommerceMedicalCardQueryResponse -> {}", JsonUtils.toJsonString(alipayCommerceMedicalCardQueryResponse));

                if (queryResponse.isSuccess(alipayCommerceMedicalCardQueryResponse)) {
                    response.setResult(alipayCommerceMedicalCardQueryResponse);
                } else {
                    request.setAccessToken(oauthTokenResponse.getAccessToken());

                    Map<String, String> bindMap = this.buildMedicareBindMap(request);
                    logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.bindMap -> {}", JsonUtils.toJsonString(bindMap));

                    String originBindParams = MapUtils.convertMap2String(bindMap);
                    logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.originBindParams -> {}", originBindParams);

                    String encodedBindParams = MapUtils.convertMap2UrlEncodeString(bindMap, request.getCharset());
                    logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.encodedBindParams -> {}", encodedBindParams);

                    String bindParams;
                    if ("RSA".equals(request.getSignType())) {
                        bindParams = encodedBindParams + "&sign=" + URLEncoder.encode(AlipaySignature.rsaSign(originBindParams, request.getPrivateKey(), request.getCharset()), request.getCharset());
                    } else {
                        bindParams = encodedBindParams + "&sign=" + URLEncoder.encode(AlipaySignature.rsa256Sign(originBindParams, request.getPrivateKey(), request.getCharset()), request.getCharset());
                    }

                    String bindUrl = this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI) + "?" + bindParams;
                    logger.info("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.bindUrl -> {}", bindUrl);

                    Map<String, String> bindUrlMap = new HashMap<>(1);
                    bindUrlMap.put("bind_url", bindUrl);

                    response.setResultCodeAndMessageAndResult(
                            ResponseEnum.ALIPAY_MEDICARE_CARD_NOT_EXIST.getCode(),
                            ResponseEnum.ALIPAY_MEDICARE_CARD_NOT_EXIST.getMessage(),
                            bindUrlMap
                    );
                }
            } else {
                response.setResultCodeAndMessage(
                        ResponseEnum.ALIPAY_OAUTH_TOKEN_FAILURE.getCode(),
                        ResponseEnum.ALIPAY_OAUTH_TOKEN_FAILURE.getMessage());
            }
        } catch (Exception e) {
            logger.error("AlipayMedicareServiceImpl.queryAlipayWebpayMedicare.Exception", e);
            response.setResultCodeAndMessage(
                    ResponseEnum.ALIPAY_MEDICARE_EXCEPTION.getCode(),
                    ResponseEnum.ALIPAY_MEDICARE_EXCEPTION.getMessage()
            );
        }

        return response;
    }

    public ResCommon<MedicareResponse> queryAlipayFacepayMedicare(MedicareVo medicareVo) throws Exception {
        logger.info("请求参数->" + JSON.toJSONString(medicareVo));

        ResCommon<MedicareResponse> response = new ResCommon<>();
        String buyerId;
        String accessToken;

        AlipayClient alipayClient = new DefaultAlipayClient(
                this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI),
                medicareVo.getAppId(),
                medicareVo.getPrivateKey(),
                medicareVo.getFormat(),
                medicareVo.getCharset(),
                medicareVo.getAlipayPublicKey());

        AlipaySystemOauthTokenRequest oauthTokenRequest = new AlipaySystemOauthTokenRequest();
        oauthTokenRequest.setCode(medicareVo.getAuthCode());
        oauthTokenRequest.setGrantType("authorization_code");
        logger.info("AlipayMedicareServiceImpl.queryAlipayFacepayMedicare.oauthTokenRequest -> {}", JsonUtils.toJsonString(oauthTokenRequest));

        try {
            AlipaySystemOauthTokenResponse oauthTokenResponse = alipayClient.execute(oauthTokenRequest);
            logger.info("AlipayMedicareServiceImpl.queryAlipayFacepayMedicare.oauthTokenResponse -> {}", JsonUtils.toJsonString(oauthTokenResponse));
            if (oauthTokenResponse != null && oauthTokenResponse.isSuccess()) {
                buyerId = oauthTokenResponse.getUserId();
                accessToken = oauthTokenResponse.getAccessToken();
            } else {
                response.setResultCodeAndMessage(ResponseEnum.ALIPAY_OAUTH_TOKEN_FAILURE.getCode(), oauthTokenResponse.getCode() + oauthTokenResponse.getMsg());
                return response;
            }
        } catch (AlipayApiException e) {
            response.setResultCodeAndMessage(
                    ResponseEnum.ALIPAY_OAUTH_TOKEN_EXCEPTION.getCode(),
                    ResponseEnum.ALIPAY_OAUTH_TOKEN_EXCEPTION.getMessage()
            );
            logger.error("AlipayMedicareServiceImpl.queryAlipayFacepayMedicare", e);
            return response;
        }

        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("method", "alipay.commerce.medical.card.query");
        dataMap.put("app_id", medicareVo.getAppId());
        dataMap.put("version", "1.0");
        dataMap.put("timestamp", DateUtils.dateToString(new Date()));
        dataMap.put("sign_type", "RSA");
        dataMap.put("sign_flag", "true");
        dataMap.put("buyer_id", buyerId);
        dataMap.put("card_org_no", "SZHRSS");
        String params = MapUtils.convertMap2String(dataMap);
        String httpParams = MapUtils.convertMap2UrlEncodeString(dataMap, "GBK");

        String sign;
        try {
            sign = AlipaySignature.rsaSign(params, medicareVo.getPrivateKey(), medicareVo.getCharset());
        } catch (AlipayApiException e) {
            logger.error("支付宝签名异常", e);
            response.setResultCodeAndMessage(ResponseEnum.ALIPAY_SIGN_FAILURE.getCode(), e.getErrMsg());
            return response;
        }

        params = httpParams + "&sign=" + URLEncoder.encode(sign, "GBK");
        String httpGetUrl = this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI) + "?" + params;
        logger.info("支付宝GET地址->" + httpGetUrl);
        String httpResult = HttpsUtil.doSslGet(httpGetUrl, "GBK");
        logger.info("支付宝GET返回->" + httpResult);
        JSONObject o = JSON.parseObject(httpResult);
        JSONObject obj = o.getJSONObject("alipay_commerce_medical_card_query_response");
        if (obj.containsKey("sign_status") && "signed".equals(obj.getString("sign_status"))) {
            response.setResultCodeAndMessage("0", "查询成功!");
            MedicareResponse medicareResponse = new MedicareResponse();
            medicareResponse.setCardOrgName(obj.getString("card_org_name"));
            medicareResponse.setMedicalCardId(obj.getString("medical_card_id"));
            return response;
        }

        //引导到绑卡的页面
        Map<String, String> bindCardDataMap = new HashMap<>();
        bindCardDataMap.put("method", "alipay.commerce.medical.instcard.bind");
        bindCardDataMap.put("app_id", medicareVo.getAppId());
        bindCardDataMap.put("version", "1.0");
        bindCardDataMap.put("timestamp", DateUtils.dateToString(new Date()));
        bindCardDataMap.put("sign_type", "RSA");
        bindCardDataMap.put("sign_flag", "true");
        bindCardDataMap.put("auth_token", accessToken);
        if (!StringUtils.isBlank(medicareVo.getReturnUrl())) {
            bindCardDataMap.put("return_url", medicareVo.getReturnUrl());
        }
        bindCardDataMap.put("buyer_id", buyerId);
        String bindCardParams = MapUtils.convertMap2String(bindCardDataMap);
        String bindCardHttpParams = MapUtils.convertMap2UrlEncodeString(bindCardDataMap, "GBK");
        String bindCardSign;
        try {
            bindCardSign = AlipaySignature.rsaSign(bindCardParams, medicareVo.getPrivateKey(), medicareVo.getCharset());
        } catch (AlipayApiException e) {
            logger.error("支付宝签名异常2", e);
            response.setResultCodeAndMessage(ResponseEnum.ALIPAY_SIGN_FAILURE.getCode(), e.getErrMsg());
            return response;
        }

        String bindCardUrl = this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI) + "?" + bindCardHttpParams + "&sign=" + URLEncoder.encode(bindCardSign, "GBK");
        response.setResultCodeAndMessage(ResponseEnum.ALIPAY_MEDICARE_CARD_NOT_EXIST.getCode(), ResponseEnum.ALIPAY_MEDICARE_CARD_NOT_EXIST.getMessage());
        MedicareResponse medicareResponse = new MedicareResponse();
        medicareResponse.setBindCardUrl(bindCardUrl);
        response.setResult(medicareResponse);

        return response;
    }

    public ResponseObject queryAlipayMedicare(String data) throws Exception {
        MedicareVo medicareVo = JsonUtils.parseObject(data, MedicareVo.class);

        ResCommon<MedicareResponse> resCommon = queryAlipayFacepayMedicare(medicareVo);

        return new ResponseObject(resCommon.getResultCode(), resCommon.getResultMessage(), resCommon.getResult());
    }

}
